package com.um.jdy.common.commons.service.impl;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.um.jdy.common.base.enums.YesOrNo;
import com.um.jdy.common.commons.service.MobileService;
import com.um.jdy.common.member.code.LoginCode;
import com.um.jdy.common.member.constants.VerificationCodeConstant;
import com.um.jdy.common.member.entity.model.CacheCodeKey;
import com.um.jdy.common.member.enums.CodeKey;
import com.um.jdy.common.member.service.ImageCodeService;
import com.um.jdy.common.platform.entity.po.App;
import com.um.jdy.common.platform.service.AppService;
import com.um.jdy.common.system.service.UserService;
import com.um.springboot.starter.constants.SmsConsts;
import com.um.springboot.starter.exception.ServiceException;
import com.um.springboot.starter.properties.AliyunSmsProperties;
import com.um.springboot.starter.properties.HshProperties;
import com.um.springboot.starter.properties.TencentSmsProperties;
import com.um.springboot.starter.service.CacheService;
import com.um.springboot.starter.service.SmsService;
import com.um.springboot.starter.utils.ImplUtil;
import com.um.springboot.starter.utils.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.LinkedHashMap;
import java.util.concurrent.TimeUnit;

/**
 * @author 邓南辉
 * 日期 2023/2/4
 * 版权所有 广州优匠科技有限公司
 */
@Service
public class MobileServiceImpl implements MobileService {

    @Value("${spring.profiles.active}")
    String profile;

    @Autowired
    CacheService cacheService;

    @Autowired
    ImageCodeService imageCodeService;

    @Autowired
    HshProperties hshProperties;

    @Autowired
    UserService userService;

    @Autowired
    AppService appService;

    /**
     * 发送短信验证码
     *
     * @param prefix
     * @param mobileAreaCode
     * @param mobile
     * @param code
     */
    public void sendCode(CodeKey prefix, String mobileAreaCode, String mobile, String code, String comId) {
        if (CodeKey.Signin != prefix && CodeKey.FindPwd != prefix) {
            imageCodeService.checkCode(code);
        }

        sendCode(prefix, mobileAreaCode, mobile, comId);
    }

    /**
     * 发送短信验证码
     *
     * @param prefix
     * @param mobileAreaCode
     * @param mobile
     */
    public void sendCode(CodeKey prefix, String mobileAreaCode, String mobile, String comId, boolean cache) {
        mobileAreaCode = StringUtil.getTrim(mobileAreaCode);

        CacheCodeKey cacheCodeKey = new CacheCodeKey(prefix, mobileAreaCode + mobile);

        Long currentTime = System.currentTimeMillis();

        if (cache) {//是否需要增加缓存来限制短信发送
//            Long sendTime = cacheService.getCacheObject(cacheCodeKey.getSendTimeKey());
//            if (null != sendTime && currentTime - sendTime < VerificationCodeConstant.CODE_INTERVAl_TIME) {
//                throw new ServiceException(LoginCode.CodeSended);
//            }

            Long sendTime = cacheService.getCacheObject(cacheCodeKey.getSendTimeKey());
            //Long currentTime = System.currentTimeMillis();
            if (null != sendTime && currentTime - sendTime < VerificationCodeConstant.CODE_INTERVAl_TIME) {
                //修改为如果code还有效时间内并未使用，则可以使用旧code
                String code = cacheService.getCacheObject(cacheCodeKey.getCodeKey());
                if(code != null)
                    return;
                else{
                    throw new ServiceException(com.um.jdy.common.platform.code.LoginCode.SendCodeRrequently);
                }
            }
        }

        // 仅生产环境才发送短信验证码
        String code = "000000";
        if ("prod".equals(profile)) {
            code = RandomUtil.randomNumbers(6);

            App app = null;
            if (StrUtil.isNotBlank(comId)) {
                app = appService.getEntity("com_id", comId);
            }
            if (app == null || StringUtil.equals(YesOrNo.No.name(), app.getSmsIsEnable())) {
                SmsService smsService;
                try {
                    smsService = ImplUtil.getSmsService();
                } catch (Exception e) {
                    throw new ServiceException(LoginCode.SmsServiceNotExist);
                }
                if (null != smsService) {
                    try {
                        if (!smsService.sendCode(mobileAreaCode, mobile, code)) {
                            throw new ServiceException(LoginCode.SendFailed);
                        }
                    } catch (Exception e) {
                        throw new ServiceException(LoginCode.SendFailed);
                    }
                }
            } else {
                SmsService smsService;
                try {
                    smsService = ImplUtil.getSmsService(app.getSmsType());
                } catch (Exception e) {
                    throw new ServiceException(LoginCode.SmsServiceNotExist);
                }

                if (null != smsService) {
                    Object smsProperties;
                    if (StringUtil.equals(SmsConsts.TENCENT_IMPL, app.getSmsType())) {
                        TencentSmsProperties tencentSmsProperties = new TencentSmsProperties();
                        tencentSmsProperties.setSecretId(app.getSmsAccessKeyId());
                        tencentSmsProperties.setSecretKey(app.getSmsAccessKeySecret());
                        tencentSmsProperties.setSignName(app.getSmsSignature());
                        tencentSmsProperties.getTemplateCodes().put(SmsConsts.VERIFICATION_CODE_TEMPLATE, app.getSmsTemplateCode());

                        smsProperties = tencentSmsProperties;
                    } else {
                        AliyunSmsProperties aliyunSmsProperties = new AliyunSmsProperties();
                        aliyunSmsProperties.setAccessKeyId(app.getSmsAccessKeyId());
                        aliyunSmsProperties.setAccessKeySecret(app.getSmsAccessKeySecret());
                        aliyunSmsProperties.setSignName(app.getSmsSignature());
                        aliyunSmsProperties.getTemplateCodes().put(SmsConsts.VERIFICATION_CODE_TEMPLATE, app.getSmsTemplateCode());

                        smsProperties = aliyunSmsProperties;
                    }

                    try {
                        LinkedHashMap<String, String> params = new LinkedHashMap<>();
                        params.put("code", code);
                        if (!smsService.send(mobileAreaCode, mobile, SmsConsts.VERIFICATION_CODE_TEMPLATE, params, smsProperties)) {
                            throw new ServiceException(LoginCode.SendFailed);
                        }
                    } catch (Exception e) {
                        throw new ServiceException(LoginCode.SendFailed);
                    }
                }
            }
        }

        cacheService.setCacheObject(cacheCodeKey.getCodeKey(), code, 1L, TimeUnit.DAYS);
        cacheService.setCacheObject(cacheCodeKey.getIdentitySendTimeKey(), currentTime, 1L, TimeUnit.DAYS);
        cacheService.setCacheObject(cacheCodeKey.getSendTimeKey(), currentTime, 1L, TimeUnit.MINUTES);

    }

    /**
     * 检查短信验证码
     *
     * @param prefix
     * @param mobile
     * @param mobileCode
     * @return
     */
    public boolean checkCode(CodeKey prefix, String mobileAreaCode, String mobile, String mobileCode) {
        mobileAreaCode = StringUtil.getTrim(mobileAreaCode);

        CacheCodeKey cacheCodeKey = new CacheCodeKey(prefix, mobileAreaCode + mobile);

        String cacheCode = cacheService.getCacheObject(cacheCodeKey.getCodeKey());
        if (null == cacheCode) {
            throw new ServiceException(LoginCode.CodeMissing);
        }
        if (!StringUtil.equals(mobileCode, cacheCode)) {
            throw new ServiceException(LoginCode.CodeError);
        }
        Long identitySendTime = cacheService.getCacheObject(cacheCodeKey.getIdentitySendTimeKey());
        if (System.currentTimeMillis() - identitySendTime > VerificationCodeConstant.CODE_EFFTIVE_TIME) {
            throw new ServiceException(LoginCode.CodeExpired);
        }

        return true;
    }

    /**
     * 废弃验证码
     *
     * @param prefix
     * @param mobileAreaCode
     * @param mobile
     */
    public void expireCode(CodeKey prefix, String mobileAreaCode, String mobile) {
        mobileAreaCode = StringUtil.getTrim(mobileAreaCode);

        CacheCodeKey cacheCodeKey = new CacheCodeKey(prefix, mobileAreaCode + mobile);

        cacheService.deleteObject(cacheCodeKey.getIdentitySendTimeKey());
        cacheService.deleteObject(cacheCodeKey.getCodeKey());
    }
}
